-- UIHeroSpeak
-- Created by chendh
-- 宠物发言窗口, 带对话框

UIHeroSpeak = class("UIHeroSpeak", function()
    return cc.Layer:create();
end);

---------------------------------------------
-- 创建强制引导窗口，附带对话框
-- @params targetForm  目标窗口
-- @params path        目标组件路径
-- @params msgList     对话内容，多段用|分隔
-- @params inEffect    飞入效果
-- @params outEffect   飞出效果
-- @params clickEffect 点击动画ID
function UIHeroSpeak.create(targetForm, heroId, msgList, inEffect, outEffect, clickEffect, endEffect, extraPara)
    return UIHeroSpeak.new(targetForm, heroId, msgList, inEffect, outEffect, clickEffect, endEffect, extraPara);
end

-- 构造函数
function UIHeroSpeak:ctor(targetForm, heroId, msgList, inEffect, outEffect, clickEffect, endEffect, extraPara)
    -- 如果窗口已存在，先关闭
    UIMgr.getCurrentScene():removeFormByName("UIHeroSpeak");

    self:setName("UIHeroSpeak");
    local node = cc.CSLoader:createNode("layout/hero/HeroSpeak.csb");
    self:addChild(node);
    self.node = node;
    self.heroId = heroId;
    self.msgList = msgList;
    self.inEffectName = inEffect;
    self.outEffectName = outEffect;
    self.clickEffect = clickEffect;
    self.endEffect = endEffect;
    self.extraPara = extraPara or {};
    self.heroName = self.extraPara.heroName or PetM.query(self.heroId, "name");

    self:setLocalZOrder(UIMgr.BONUS_NOTIFY_ZORDER + 1);

    self:resize();

    -- 注册点击处理函数
    self:registerTouchEvent();

    -- 注册事件回调处理函数
    self:registerEventCallback();

    -- 记录文本框位置
    self.textLabel = findChildByName(self.node, "CT/guide/dialogue_bg/panel/text");
    self.oldTextLabelPos = cc.p(self.textLabel:getPosition());

    local guide = findChildByName(self.node, "CT/guide");
    self.guide = guide;

    local function callback()
        -- 显示文字效果
        self:showText();
    end

    -- 初始化对话内容
    self:initDialogue();

    -- 运行入场效果
    self:runInEffect(callback);
end

-- 注册点击处理函数
function UIHeroSpeak:registerTouchEvent()
    local rectNode = findChildByName(self.node, "panel/rect");

    local panel = findChildByName(self.node, "panel");
    local function onCloseClick(sender, eventType)
        if eventType == ccui.TouchEventType.began then
            if not self.isFinished then
                -- 当前文字还没显示完毕
                self:skipSection();
                return;
            end

            if #self.msgList > 0 then
                -- 开始下一段对话
                self:showNextSection();
                return;
            end

            if self.targetNode then
                local rect = rectNode:getBoundingBox();

                local locationInNode = panel:convertToNodeSpace(sender:getTouchBeganPosition());
                if cc.rectContainsPoint(rect, locationInNode) then
                    -- 在目标范围区域， 设置消息穿透
                    panel:setSwallowTouches(false);
                    return false;
                end

                -- 不在目标范围区域， 吃掉消息
                panel:setSwallowTouches(true);

                -- 播放涟漪效果
                playEffect(panel, 1175, locationInNode.x, locationInNode.y);

                return true;
            else
                -- 关闭窗口
                self:closeForm();
            end
        end
    end
    panel:addTouchEventListener(onCloseClick);
end

-- 注册事件回调处理函数
function UIHeroSpeak:registerEventCallback()
    self:registerScriptHandler(function(event)
        if event == "exit" then
            -- turnFormDark(targetForm, false, { });
            EventMgr.removeAll("UIHeroSpeak");
        end
    end);
end

-- 初始化对话内容
function UIHeroSpeak:initDialogue()
    local guide = self.guide;

    if #self.msgList == 0 then
        guide:setVisible(false);

        -- 没有配置说话内容，直接跳过
        self.isFinished = true;
        return;
    end

    guide:setVisible(true);

    -- 显示名称
    local nameLabel = findChildByName(guide, "dialogue_bg/name");
    TextStyleM.setTextStyle(nameLabel, TextStyleM.TEXT_SIZE_SMALL, TextStyleM.TEXT_COLOR_GREEN, false);
    nameLabel:setString(self.heroName);

    -- 头像
    local headIcon = findChildByName(guide, "head_icon");
    if self.display == nil then
        local heroId = self.heroId;
        local modelId = PetM.query(heroId, "default_model");
        if self.extraPara["modelId"] then
            -- 有传进来的参数
            modelId = self.extraPara["modelId"];
        end

        local offsetX = PetM.queryModel(modelId, "offset_x");
        local offsetY = PetM.queryModel(modelId, "offset_y");

        local iconPath = getHeroLargeIconPath(PetM.getDefaultIcon(heroId));
        local heroIcon = findChildByName(headIcon, "hero_icon");
        local heroModel = findChildByName(headIcon, "hero_model");
        local modelAnim = createHeroModel(modelId, heroIcon, heroModel, 0.6, iconPath, offsetX, offsetY);
        heroIcon:setScale(0.8);
        self.display = modelAnim;

        if modelAnim ~= nil then
            local function playAtkAnim()
                local rand = math.random(1, 2);
                local heroDisplay = findChildByName(heroModel, "HeroDisplay");

                if rand == 1 then
                    -- 播放施法动作
                    heroDisplay:switchAction(HERO_ACTION_CAST_ME);
                else
                    -- 播放攻击动作
                    heroDisplay:switchAction(HERO_ACTION_ATTACK);
                end

                -- 延迟播放攻击动作
                local delayFix = math.random(5, 10);
                performWithDelay(heroModel, playAtkAnim, delayFix);
            end

            playAtkAnim();
        end
    end

    -- 对话框初始不可见
    local dialogue = findChildByName(self.guide, "dialogue_bg");
    dialogue:setVisible(false);

    -- 判断是否是复活
    local isRevive = PetM.isReviveSlime(self.heroId) and DungeonM.isInDungeon();
    self.isRevive = isRevive;

    -- 如果是复活，则蒙版要加深
    local bg2 = findChildByName(self.node, "bg2");
    if isRevive then
        bg2:setVisible(true);
    else
        bg2:setVisible(false);
    end
end

-- 初始化文本
function UIHeroSpeak:showText()
    if #self.msgList == 0 then
        self.guide:setVisible(false);

        -- 没有配置说话内容，直接跳过
        self.isFinished = true;
        return;
    end

    self.textLabel:setPosition(self.oldTextLabelPos);

    -- 显示文本
    local textScale = 1;
    if getLang() == "th" then
        textScale = 0.85;
    end
    TextStyleM.setTextStyle(self.textLabel, TextStyleM.TEXT_SIZE_SMALL, TextStyleM.TEXT_COLOR_DARK_BROWN, false, nil, nil, nil, nil, TextStyleM.TEXT_SIZE_SMALL, nil, textScale);
    self.textLabel = applyString(self.textLabel, self.msgList[1]);

    -- 收集字符列表
    self:collectLetters();

    -- 删除初始化过的
    table.remove(self.msgList, 1);

    -- 播放文字效果
    performWithDelay(self, function() self:playTextEffect() end, 0.1);
end

-- 适配
function UIHeroSpeak:resize()
    local node = self.node;
    AlignM.fitToScreen(node, "bg");
    AlignM.fitToScreen(node, "bg2");

    AlignM.alignToCenter(node, "CT");
    AlignM.alignToCenter(node, "panel");
end

-- 收集字符列表
function UIHeroSpeak:collectLetters()
    local textLabel = self.textLabel;
    local text = self.msgList[1];

    local count = string.getWCharCount(text);
    self.letters = {};

    local i = 0;
    local endPos = count - 1;
    local charPos = 0;
    local curPaddingCount = 0;
    while i <= endPos do
        local letter = textLabel:getVirtualRenderer():getLetter(i);
        local nextLetter = textLabel:getVirtualRenderer():getLetter(i+1);
        if letter then
            -- 初始所有字符置为不可见
            letter:setOpacity(0);

            -- 加入到字符列表
            table.insert(self.letters, 1, i);
        else
            if nextLetter ~= nil and not string.isBreakLineChar(text, charPos-curPaddingCount) then
                -- 如果是系统自动添加的换行符，需要把结束位置往后挪
                endPos = endPos + 1;
                curPaddingCount = curPaddingCount + 1;
            end
        end

        i = i + 1;
        charPos = charPos + 1;
    end
end

-- 对话效果，一个字一个字慢慢播放
function UIHeroSpeak:playTextEffect()
    -- 开始说话效果
    --self.display:gotoTalk();
    --self.animation:play(true, 24, 45, 0.5);

    local function play()
        if #self.letters > 0 then
            local pos = self.letters[#self.letters];
            local letter = self.textLabel:getVirtualRenderer():getLetter(pos);
            table.remove(self.letters, #self.letters);
            local fadeIn = cc.FadeIn:create(0.1);
            local callFunc = cc.CallFunc:create(function()
                if 0 == #self.letters then
                    -- 箭头开始上下动
                    self:playArrowEffect();

                    -- 停止说话效果
                    --self.display:gotoIdle();

                    -- 标记字体播放完成
                    self.isFinished = true;
                end
            end);

            self.isFinished = false;
            if letter then
                letter:runAction(cc.Sequence:create(fadeIn, callFunc));
            end
            performWithDelay(self.textLabel, play, 0.1);
        end
    end

    play();
end

-- 播放下一段对话
function UIHeroSpeak:showNextSection()
    local moveTo = cc.MoveBy:create(0.2, cc.p(0, 85));
    local callFunc = cc.CallFunc:create(function()
        if #self.msgList > 0 then
            -- 开始下一段讲话
            self:showText();

            -- 播放文字效果
            self:playTextEffect();
        end
    end);

    self.textLabel:runAction(cc.Sequence:create(moveTo, callFunc));
end

-- 文字立刻显示
function UIHeroSpeak:skipSection()
    self.textLabel:stopAllActions();

    if self.letters == nil then
        return;
    end

    while #self.letters > 0 do
        local pos = self.letters[#self.letters];
        local letter = self.textLabel:getVirtualRenderer():getLetter(pos);
        table.remove(self.letters, #self.letters);

        if letter then
            letter:setOpacity(255);
        end

        if 0 == #self.letters then
            -- 箭头开始上下动
            self:playArrowEffect()

            -- 标记字体播放完成
            self.isFinished = true;
        end
    end
end

-- 箭头上下移动
function UIHeroSpeak:playArrowEffect()
    local arrow = findChildByName(self.guide, "dialogue_bg/arrow");
    if #self.msgList > 0 then
        arrow:setVisible(true);
        if not arrow.isPlaying then
            local oldPos = cc.p(arrow:getPosition());

            local moveDown = cc.MoveTo:create(0.5, cc.pAdd(oldPos, cc.p(0, -3)));
            local moveBack = cc.MoveTo:create(0.5, oldPos);
            arrow:runAction(cc.RepeatForever:create(cc.Sequence:create(moveDown, moveBack)));
            arrow.isPlaying = true;
        end
    else
        -- 显示手势指引，隐藏箭头
        local hand = findChildByName(self.node, "panel/rect/hand");
        hand:setVisible(true);
        arrow:setVisible(false);
        arrow:pause();
    end
end

-- 关闭窗口
function UIHeroSpeak:closeForm()
    -- 运行关闭窗口效果
    local function callback()
        if self.endEffect ~= nil then
            self:endEffectPlay();
        end

        -- 回调!
        if type(self.extraPara["endCallback"]) == "function" then
            self.extraPara["endCallback"]();
        end
        -- 如果是复活，则播放复活光效
        if self.isRevive then
            -- 背景淡出
            local outTime = 1;
            local bg = findChildByName(self.node, "bg");
            local fadeOut = cc.FadeOut:create(outTime);
            bg:runAction(fadeOut);

            local bg2 = findChildByName(self.node, "bg2");
            local fadeOut = cc.FadeOut:create(outTime);

            local callFunc = cc.CallFunc:create(function()
                -- 移除界面
                UIMgr.getCurrentScene():removeFormByName("UIHeroSpeak");
            end);

            bg2:runAction(cc.Sequence:create(fadeOut, callFunc));

            -- 播放复活光效
            playHeroReviveEffect();
        else
            UIMgr.getCurrentScene():removeFormByName("UIHeroSpeak");
        end
    end
    self:runOutEffect(callback);
end

-- 关闭界面后效果
function UIHeroSpeak:endEffectPlay()
    if type(self.endEffect) == 'function' then
        self.endEffect();
        return;
    end

    if self.endEffect == "gain_pet" then
        -- 获得冈布奥
        local uiHeroInfo = UIHeroGainEffect.create(self.heroId);
        UIMgr.getCurrentScene():addForm(uiHeroInfo);
    else
        -- 获得物品
        self:getItemEffect();
    end
end

-- 物品获得
function UIHeroSpeak:getItemEffect()
    local bonus = self.endEffect;
    if self.isRevive then
        playGainItemByHeroSpeak(bonus, getLocStr("get_spokesman_bonus"));
    else
        AudioM.playFx("button_receive");
        local bonusTitle = getLocStr("black_marker_bonus");

        if self.extraPara["bonusTitle"] then
            bonusTitle = self.extraPara["bonusTitle"];
        end
        showBonusNotifyForm(bonusTitle, bonus, nil, nil, nil, nil, nil, self.extraPara["exitFunc"]);
    end
end

-- 运行入场效果
function UIHeroSpeak:runInEffect(callback)
    if self.inEffectName == nil or self.inEffectName == "" then
        local dialogue = findChildByName(self.guide, "dialogue_bg");
        dialogue:setVisible(true);

        callback();
        return;
    end

    if self.inEffectName == "B_FLY_IN" then
        -- 勇者冈布奥飞入
        self:braveSlimeFlyIn(callback);
    else
        print("入场效果未支持："..self.inEffectName);
    end
end

-- 勇者冈布奥飞入
function UIHeroSpeak:braveSlimeFlyIn(callback)
    -- 勇者冈布奥飞入
    local headIcon = findChildByName(self.guide, "head_icon");
    local oldPos = cc.p(headIcon:getPosition());
    headIcon:setPositionX(oldPos.x + DESIGN_WIDTH);
    local move1 = cc.MoveTo:create(0.2, cc.p(oldPos.x - 10, oldPos.y));
    local move2 = cc.MoveTo:create(0.2, cc.p(oldPos.x, oldPos.y));
    local delay = cc.DelayTime:create(0.1);
    local callFunc = cc.CallFunc:create(function()
        -- 对话框慢慢变大
        local dialogue = findChildByName(self.guide, "dialogue_bg");
        local panel = findChildByName(self.guide, "dialogue_bg/panel");
        dialogue:setVisible(true);
        panel:setVisible(false);
        dialogue:setScale(0.3);
        local scaleUp = cc.ScaleTo:create(0.2, 1);
        local done = cc.CallFunc:create(function()
            panel:setVisible(true);
            callback();
        end);
        dialogue:runAction(cc.Sequence:create(scaleUp, done));
    end);
    headIcon:runAction(cc.Sequence:create(move1, move2, delay, callFunc));
end

-- 运行离开效果
function UIHeroSpeak:runOutEffect(callback)
    local panel = findChildByName(self.node, "panel");
    panel:setSwallowTouches(true);
    panel:addTouchEventListener(function(sender, eventType) end);

    if self.outEffectName == nil or self.outEffectName == "" then
        callback();
        return;
    end

    if self.isRunningOutEffect then
        return;
    end

    if self.outEffectName == "B_FLY_OUT" then
        -- 勇者冈布奥飞出
        self:braveSlimeFlyOut(callback);
    else
        print("出场效果未支持："..self.outEffectName);
    end

    self.isRunningOutEffect = true;
end

-- 勇者冈布奥飞离
function UIHeroSpeak:braveSlimeFlyOut(callback)
    -- 对话框消失
    local dialogue = findChildByName(self.guide, "dialogue_bg");
    dialogue:setVisible(false);

    -- 勇者冈布奥飞离
    local headIcon = findChildByName(self.guide, "head_icon");
    local oldPos = cc.p(headIcon:getPosition());
    local move = cc.MoveTo:create(0.2, cc.p(oldPos.x + DESIGN_WIDTH, oldPos.y));
    local callFunc = cc.CallFunc:create(function()
        callback();
    end);
    headIcon:runAction(cc.Sequence:create(move, callFunc));
end

